package com.ilxqx.fierce.core;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.ilxqx.fierce.exception.FierceRequestException;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.TypeConverter;
import org.springframework.core.convert.converter.Converter;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;

import java.lang.reflect.Field;
import java.util.Map;

/**
 * Map到对象转换器
 *
 * @author Venus
 * @since 1.0.0
 */
@RequiredArgsConstructor
public class Map2ObjConverter<T> implements Converter<Map<String, Object>, T> {
    private final Class<?> objClass;
    /**
     * Convert the source object of type {@code S} to target type {@code T}.
     *
     * @param source the source object to convert, which must be an instance of {@code S} (never {@code null})
     * @return the converted object, which must be an instance of {@code T} (potentially {@code null})
     * @throws IllegalArgumentException if the source cannot be converted to the desired target type
     */
    @Nullable
    @Override
    @SuppressWarnings("unchecked")
    public T convert(@NonNull Map<String, Object> source) {
        TypeConverter typeConverter = FierceRequestProcessingSupport.getTypeConverter();
        Field[] fields = ReflectUtil.getFields(this.objClass);
        Object instance = ReflectUtil.newInstance(this.objClass);
        for (Field field : fields) {
            if (!source.containsKey(field.getName())) {
                continue;
            }

            Object value = source.get(field.getName());
            if (value == null) {
                if (field.getType().isPrimitive()) {
                    throw new FierceRequestException(
                        StrUtil.format(
                            "字段[{}.{}({})]无法映射空值！",
                            field.getDeclaringClass().getSimpleName(),
                            field.getName(),
                            field.getType().getSimpleName()
                        )
                    );
                }
                continue;
            }

            ReflectUtil.setFieldValue(
                instance,
                field,
                typeConverter.convertIfNecessary(value, field.getType())
            );
        }

        return (T) instance;
    }
}
